#include "Acceptor.h"
#include <sys/types.h>
#include <sys/socket.h>
#include "Logger.h"
#include <unistd.h>
#include "InetAddress.h"

static int createNonblocking() {
    // 创建了listenfd
    int sockfd = ::socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, IPPROTO_TCP);
    if (sockfd < 0) {
        LOG_FATAL("listen socketfd create error\n");
    }

    return sockfd;
}

Acceptor::Acceptor(EventLoop *loop, const InetAddress& listenAddr, bool reuseport) // listenAddr是要绑定到网络上的地址，等待客户端连接
    : loop_(loop)
    , acceptSocket_(createNonblocking())
    , acceptChannel_(loop, acceptSocket_.fd()) // 传入mainloop和listenfd
    , listenning_(false)
{
    acceptSocket_.setReuseAddr(true);
    acceptSocket_.setReusePort(true);

    acceptSocket_.bindAddress(listenAddr);

    //有新用户连接时，connfd需要打包成channel再唤醒subloop，交给subloop的poller监听读写事件
    // baseLoop监听到读事件，即连接事件
    acceptChannel_.setReadCallback(std::bind(&Acceptor::handleRead, this));
}

Acceptor::~Acceptor() {
    acceptChannel_.disableAll();
    acceptChannel_.remove();
}


void Acceptor::listen() {
    listenning_ = true;
    acceptSocket_.listen();
    acceptChannel_.enableReading(); // 丢到Poller监听
}


// listenfd有连接事件发生(mainloop上)，就会调用此函数
void Acceptor::handleRead() {
    InetAddress peerAddr(0);
    int connfd = acceptSocket_.accept(&peerAddr); // 返回后，connfd是accept返回的和client通信的fd，peerAddr存储的是client的地址信息
    if (connfd >= 0) {
        if (newConnectionCallback_) {
            newConnectionCallback_(connfd, peerAddr); // 轮询找到subloop 唤醒 分发当前新客户端连接的channel
            // 创建TcpConnection维护两端通信资源
        } else {
            ::close(connfd);
        }
    } else {
        LOG_ERROR("Acceptor::handleRead() error\n");
        if (errno == EMFILE) {
            LOG_ERROR("Acceptor::handleRead() EMFILE error\n");
        }
    }
}